Crate generativity

source ·
Expand description

Create a trusted carrier with a new lifetime that is guaranteed to be unique among other trusted carriers. When you call make_guard! to make a unique lifetime, the macro creates a Guard to hold it. This guard can be converted into an Id, which can be stored in structures to uniquely “brand” them. A different invocation of the macro will produce a new lifetime that cannot be unified. The only way to construct these types is with make_guard! or unsafe code.

use generativity::{Id, make_guard};
struct Struct<'id>(Id<'id>);
make_guard!(a);
Struct(a.into());

This is the concept of “generative” lifetime brands. Guard and Id are invariant over their lifetime parameter, meaning that it is never valid to substitute or otherwise coerce Id<'a> into Id<'b>, for any concrete 'a or 'b, including the 'static lifetime.

Any invariant lifetime can be “trusted” to carry a brand, so long as they are known to be restricted to carrying a brand, and haven’t been derived from some untrusted lifetime (or are completely unbound). When using this library, it is recommended to always use Id<'id> to carry the brand, as this reduces the risk of accidentally trusting an untrusted lifetime. Importantly, non-invariant lifetimes cannot be trusted, as the variance allows lifetimes to be contracted to match and copy the brand lifetime.

To achieve lifetime invariance without Id, there are two standard ways: PhantomData<&'a mut &'a ()> and PhantomData<fn(&'a ()) -> &'a ()>. The former works because &mut T is invariant over T, and the latter works because fn(T) is contravariant over T and fn() -> T is covariant over T, which combines to invariance. Both are equivalent in this case with T = (), but fn(T) -> T is generally preferred if the only purpose is to indicate invariance, as function pointers are a perfect cover for all auto traits (e.g. Send, Sync, Unpin, UnwindSafe, etc.) and thus only indicates invariance, whereas &mut T can carry further implication of “by example” use of PhantomData.

Macros

  • Create a Guard with a unique invariant lifetime (with respect to other trusted/invariant lifetime brands).

Structs

  • An invariant lifetime phantomdata-alike that is guaranteed to be unique with respect to other trusted invariant lifetimes.
  • A phantomdata-like type taking a single invariant lifetime.